package models

import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"time"
)

type SheetData struct {
	sourceReader  *ExcelParser
	Fields        string
	UrlSheet      string
	Result        string
	Records       int
	ComputeID     int64
	ComputedArray []interface{}
}

type SheetFields struct {
	Name       string   `json:"name"`
	Fields     []string `json:"fields"`
	fieldArray map[string]int
}

var AllExcelSheets map[string]SheetData
var ComputedSheets map[int64]SheetData

func init() {
	AllExcelSheets = make(map[string]SheetData)
	ComputedSheets = make(map[int64]SheetData)
}

func SetSheetRecordFromFile(excelReader *ExcelParser, fileName string) error {
	var sheet SheetData

	if excelReader == nil {
		return errors.New("excel reader is nil")
	}

	sheet.sourceReader = excelReader
	sheet.Fields = excelReader.GetFormatFields()
	AllExcelSheets[fileName] = sheet

	return nil
}

func computeUniqMap(exlRaw []interface{}, field string) map[string]interface{} {
	tempUniq := make(map[string]interface{})
	for _, v := range exlRaw {
		node := v.(map[string]interface{})
		if node[field] != nil {
			var val string
			switch reflect.TypeOf(node[field]).Kind() {
			case reflect.Float64:
				tmp := node[field].(float64)
				val = strconv.FormatFloat(tmp, 'f', -1, 64)
			case reflect.String:
				val = node[field].(string)
			}
			tempUniq[val] = v
		} else {
			tempUniq[""] = v
		}
	}

	return tempUniq
}

func UniqSheetOneCol(fileName string, field string, computeArr []interface{}) ([]interface{}, error) {
	var exlRaw []interface{}
	var computedArray = make([]interface{}, 0)

	if len(computeArr) > 0 {
		exlRaw = computeArr
	} else {
		oneSheet := AllExcelSheets[fileName]
		exlRaw = oneSheet.sourceReader.GetRowsArray()
	}

	tempUniq := computeUniqMap(exlRaw, field)
	for _, v := range tempUniq {
		computedArray = append(computedArray, v)
	}

	return computedArray, nil
}

func LocationCompute(fileName, field string, computeArr []interface{}) ([]interface{}, error) {
	var exlRaw []interface{}

	if len(computeArr) > 0 {
		exlRaw = computeArr
	} else {
		oneSheet := AllExcelSheets[fileName]
		exlRaw = oneSheet.sourceReader.GetRowsArray()
	}

	tempUniq := computeUniqMap(exlRaw, field)
	// generate number array
	numbers := make([]string, 0)
	for k, _ := range tempUniq {
		if IsValidPhoneNumber(k) {
			numbers = append(numbers, k)
		}
	}

	fmt.Println("numbers len: ", len(numbers))

	retLocateMap, err := GetLocation(numbers)
	if err != nil {
		return nil, err
	}

	if len(retLocateMap) == 0 {
		return nil, errors.New("接口无数据返回")
	}

	var computedArray = make([]interface{}, 0)

	for k, v := range retLocateMap {
		node, ok := tempUniq[k]
		if ok {
			rows := node.(map[string]interface{})
			locateVal := k + "归属地"
			rows[locateVal] = interface{}(v)
			computedArray = append(computedArray, interface{}(rows))
		}
	}

	return computedArray, err
}

func SetComputedResult(fileName string, arr []interface{}, field string) int64 {
	var computeID int64 = -1

	oneSheet, ok := AllExcelSheets[fileName]
	if ok {
		computeID = time.Now().UnixNano()
		oneSheet.ComputedArray = arr
		if len(field) > 0 {
			oneSheet.Fields = field
		}
		ComputedSheets[computeID] = oneSheet
	}

	return computeID
}

func GetResponseData(computeID int64) SheetData {
	var ret SheetData

	ret.Fields = ComputedSheets[computeID].Fields
	ret.Records = len(ComputedSheets[computeID].ComputedArray)
	ret.ComputeID = computeID
	ret.UrlSheet = "/content.do?id=" + strconv.FormatInt(computeID, 10)
	ret.Result = "OK"

	return ret
}

func GetTestArrayCount() int {
	reader := AllExcelSheets["huge.xlsx"]
	return len(reader.sourceReader.sourceArray)
}

func GetTestArrayData() []interface{} {
	reader := AllExcelSheets["huge.xlsx"]
	return reader.sourceReader.sourceArray
}

func GetComputedArrayConut(cid int64) int {
	return len(ComputedSheets[cid].ComputedArray)
}

func GetComputedArrayData(cid int64, page int, limit int) []interface{} {
	count := GetComputedArrayConut(cid)
	items := page * limit
	if items > count || limit == 0 {
		items = count
	}

	return ComputedSheets[cid].ComputedArray[(page-1)*limit : items]
}

func IntersectionCompute(fields string) (int64, error) {
	var exlField []SheetFields

	err := json.Unmarshal([]byte(fields), &exlField)
	if err != nil {
		return 0, err
	}

	specialName := exlField[0].Name
	specialField := exlField[0].Fields[0]

	// build all field index
	tempIndex := make([]map[string]interface{}, 0)
	for _, v := range exlField {
		for _, fd := range v.Fields {
			node := computeUniqMap(AllExcelSheets[v.Name].sourceReader.GetRowsArray(), fd)
			tempIndex = append(tempIndex, node)
		}
	}

	if len(tempIndex) <= 1 {
		return 0, errors.New("字段数必须大于1")
	}

	// intersection process
	resultArray := make([]interface{}, 0)
	primaryIndex := tempIndex[0]
	compareIndex := tempIndex[1:]
	allInter := len(tempIndex) - 1

	for k, _ := range primaryIndex {
		correct := 0
		for _, v := range compareIndex {
			_, ok := v[k]
			if ok {
				correct++
			} else {
				break
			}
		}
		if correct == allInter {
			elem := make(map[string]string)
			elem[specialField] = k
			resultArray = append(resultArray, interface{}(elem))
		}
	}

	// set result to computed array
	var computeID int64 = 0
	if len(resultArray) > 0 {
		resultField := `["` + specialField + `"]`
		computeID = SetComputedResult(specialName, resultArray, resultField)
	}

	return computeID, nil
}
